home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / zmdm / transfer.c < prev    next >
C/C++ Source or Header  |  1993-06-26  |  15KB  |  873 lines

  1. /*
  2.  *     Transfer Shell
  3.  *
  4.  *        Jwahar Bammi
  5.  *            usenet: cwruecmp!bammi@decvax.UUCP
  6.  *            csnet:  bammi@cwru.edu
  7.  *            arpa:   bammi@cwru.edu
  8.  *            CompuServe: 71515,155
  9.  */
  10.  
  11. #include "zmdm.h"
  12. #include "common.h"
  13.  
  14. /* #define DEBUG 1 */
  15.  
  16. #define ISWILD(X)    ((X == '*')||(X == '?'))
  17. #define PROMPT        fprintf(stderr,"zmdm> ")
  18.  
  19. extern int dorz(), dosz(), ls(), rm(), cp(), cd(), md(), rd(), pwd(), df(),
  20.        hhelp();
  21. #ifdef RECURSE
  22. extern int doszf();
  23. #endif
  24.  
  25. static struct comnds {
  26.     char    *command;    /* command string    */
  27.     int     (*routine)();    /* routine to invoke    */
  28.     char    *synopsis;    /* synopsis        */
  29.     int    expand;        /* expand wildcards before calling routine? */
  30. } comtab [] = {
  31.     { "rz",    dorz, "receive files using Z/X modem protocol",       TRUE },
  32.     { "rb", dorz, "receive files using Y modem protocol",         TRUE },
  33. #ifdef RECURSE
  34.     { "sz", doszf, "send files using Z/Y/X modem protocol",        TRUE },
  35. #else
  36.     { "sz", dosz, "send files using Z/Y/X modem protocol",        TRUE },
  37. #endif
  38.     { "sb", dosz, "send files using Y modem protocol",            TRUE },
  39.     { "rm", rm,   "remove files",                                 TRUE },
  40.     { "cp", cp,   "copy files",                                   TRUE },
  41.     { "ls", ls,   "list directory",                               FALSE},
  42.     { "cd", cd,   "change working directory",             FALSE},
  43.     { "md", md,   "make a directory",                 FALSE},
  44.     { "rd", rd,   "remove a directory",                     FALSE},
  45.     { "pwd",pwd,  "print  working directory",             FALSE},
  46.     { "df", df,   "check free space",                 FALSE},
  47.     { "?",  hhelp, "this message",                     FALSE},
  48.     { (char *)NULL, (int (*)())NULL, (char *)NULL,                   FALSE}
  49. };
  50.  
  51. #define MAXARGS    1024
  52. static char *targv[MAXARGS];
  53. static int targc;
  54. char *alltolower();
  55.  
  56. transfer()
  57. {
  58.     char linebuf[132];
  59.     char *line;
  60.     int command;
  61.     int status;
  62.     extern int find_command();
  63.     extern int expnd_args();
  64. #ifdef DEBUG
  65.     int i;
  66. #endif
  67.  
  68.     fprintf(stderr,"hit <RETURN> to return to emulator,  <?> for help\n\n");
  69.     targc = 0;
  70.     while (TRUE)
  71.     {
  72.         if(targc > 1)
  73.             free_args();
  74.  
  75.         PROMPT;
  76.         linebuf[0] = 127;
  77.         Cconrs(linebuf);
  78.         putc('\n', stderr);
  79.         if(linebuf[1] == 0)
  80.         /* cancelled */
  81.         return;
  82.         
  83.         linebuf[(linebuf[1]+2)] = '\0';
  84.         line = &linebuf[2];
  85. #ifdef DEBUG
  86. printf("Line: |%s|\n", line);
  87. #endif
  88.  
  89.         targv[0] = line;
  90.         targc    = 1;
  91.     
  92.         /* pick up targv[0] */
  93.         while((*line != '\0') && (!isspace(*line)))
  94.             line++;
  95.  
  96.         if(*line != '\0')
  97.         {
  98.             *line++ = '\0';
  99.         }
  100.  
  101.         if((command = find_command(targv[0])) < 0)
  102.         {
  103.             fprintf(stderr,"Invalid Command\n");
  104.             continue;
  105.         }
  106.  
  107.         if(expnd_args(line, comtab[command].expand))
  108.             /* too many args */
  109.             continue;
  110. #ifdef DEBUG
  111. printf("targc %d\n", targc);
  112. for(i = 0; i < targc; i++)
  113.     printf("%s ", targv[i]);
  114. printf("\n\n");
  115. #endif
  116.  
  117.         if((status = (*(comtab[command].routine))(targc, targv)) != 0)
  118.             fprintf(stderr,"Exit Status %d\n", status);
  119.  
  120. #ifdef DEBUG
  121. printf("Exit Status %d\n", status);
  122. #endif
  123.  
  124.     } /* While */
  125. }
  126.  
  127. /*
  128.  * Straight sequential search thru comtab
  129.  */        
  130. int find_command(s)
  131. register char *s;
  132. {
  133.     register int i;
  134.  
  135.     for(i = 0; comtab[i].command != (char *)NULL; i++)
  136.     {
  137.         if(strcmp(s, comtab[i].command) == 0)
  138.             return i;
  139.     }
  140.  
  141.     return -1;
  142. }
  143.  
  144. /*
  145.  * Expand command line args, return TRUE if too many args, or Not matching Quotes
  146.  */
  147. int expnd_args(s, expand_wild)
  148. register char *s;
  149. int expand_wild;
  150. {
  151.     char next_arg[128];
  152.     register char *p;
  153.     register int contains_wild;
  154.     extern int add_argv();
  155.     extern int handl_wild();
  156.  
  157.     while(*s != '\0')
  158.     {
  159.         p = next_arg;
  160.         while(isspace(*s)) s++; /* skip leading space */
  161.         if(*s != '\0')
  162.         {
  163.             contains_wild = FALSE;
  164.             if(*s == '\047')
  165.             {
  166.                 /* Quoted arg */
  167.                 s++;
  168.                 while((*s != '\0') && (*s != '\047'))
  169.                     *p++ = *s++;
  170.                 *p = '\0';
  171.                 if(*s == '\0')
  172.                 {
  173.                     fprintf(stderr,"No Matching Quote\n");
  174.                     return TRUE;
  175.                 }
  176.                 else
  177.                     s++;
  178.                 if(add_argv(next_arg))
  179.                     return TRUE;
  180.             }
  181.             else
  182.             {
  183.                 while(!isspace(*s) && (*s != '\0'))
  184.                 {
  185.                     contains_wild |= ISWILD(*s);
  186.                     *p++ = *s++;
  187.                 }
  188.                 *p = '\0';
  189.  
  190.                 if(contains_wild && expand_wild)
  191.                 {
  192.                     if(handl_wild(next_arg))
  193.                         return TRUE;
  194.                 }
  195.                 else
  196.                 {
  197.                     if(add_argv(next_arg))
  198.                         return TRUE;
  199.                 }
  200.             } /* if-else */
  201.         } /* If */
  202.     } /* while */
  203.  
  204.     return FALSE;
  205. }
  206.  
  207. /*
  208.  * add an arg to argv. Return TRUE if error
  209.  */
  210. int add_argv(s)
  211. char *s;
  212. {
  213.     extern char *myalloc();
  214.     extern char *strcpy();
  215.     extern int strlen();
  216.  
  217.     if(targc > (MAXARGS-1))
  218.     {
  219.         fprintf(stderr,"Too many arguements (%d Max)\n", MAXARGS);
  220.         return TRUE;
  221.     }
  222.     targv[targc++] = strcpy(myalloc(strlen(s)+1), s);
  223.     
  224.     return FALSE;
  225.     
  226. }
  227.  
  228. /*
  229.  * expand wild card arguments. Return TRUE on error.
  230.  */
  231. int handl_wild(s)
  232. char *s;
  233. {
  234.     extern struct stat statbuf;
  235.     extern char *mkpathname();
  236.     
  237.     if(Fsfirst(s, 0x21) != 0)
  238.     {
  239.         /* No match */
  240.         fprintf(stderr,"No Match for %s\n", s);
  241.         return TRUE;
  242.     }
  243.  
  244.     alltolower(statbuf.st_name);
  245.     if(add_argv(mkpathname(s, statbuf.st_name)))
  246.         return TRUE;
  247.  
  248.     while(Fsnext() == 0)
  249.     {
  250.         alltolower(statbuf.st_name);
  251.         if(add_argv(mkpathname(s, statbuf.st_name)))
  252.             return TRUE;
  253.     }
  254.  
  255.     return FALSE;
  256. }
  257.  
  258. /*
  259.  * Given a spec with a trailing wildcard and a base will name construct pathname
  260.  *
  261.  */
  262. char *mkpathname(spec, file)
  263. register char *spec, *file;
  264. {
  265.     extern char *rindex();
  266.     register char *p;
  267.  
  268.     if((p = rindex(spec, '\\')) == (char *)NULL)
  269.         /* no path name */
  270.         return file;
  271.  
  272.     while(*file != '\0')
  273.         *++p = *file++;
  274.     *++p = '\0';
  275.     
  276.     return spec;
  277. }
  278.  
  279. free_args()
  280. {
  281.     register int i;
  282.     
  283.     for(i = 1; i < targc; i++)
  284.         free(targv[i]);
  285. }
  286.  
  287. /*
  288.  * remove files
  289.  *    Usage: rm [-i] files ... 
  290.  */    
  291. int rm(argc, argv)
  292. register int argc;
  293. register char **argv;
  294. {
  295.     register int interactive;
  296.     register int status, s;
  297.     extern int yesno();
  298.     extern int errno;
  299.  
  300.     interactive = FALSE;
  301.     status = 0;
  302.     while(--argc)
  303.     {
  304.         ++argv;
  305.         if( ((*argv)[0] == '-') && ((*argv)[1] == 'i') )
  306.             interactive = TRUE;
  307.         else
  308.         {
  309.             if(interactive)
  310.                 if(!yesno("rm: remove", *argv))
  311.                     continue;
  312.             if(unlink(*argv))
  313.             {
  314.                 s |= 1;
  315.                 fprintf(stderr, "%s: no such file\n", *argv);
  316.             }
  317.             status |= s;
  318.         }
  319.     }
  320.     return status;
  321. }
  322.  
  323. /*
  324.  * Prompt and return Yes/No truth value
  325.  *
  326.  */
  327. int yesno(p1, p2)
  328. register char *p1, *p2;
  329. {
  330.     char reply[16];
  331.  
  332.     fprintf(stderr,"%s %s (y/n): ", p1, p2);
  333.     reply[0] = 16;
  334.     Cconrs(reply);
  335.     putc('\n', stderr);
  336.     return ( (reply[2] == 'y') || (reply[2] == 'Y') );
  337.  
  338. }
  339.  
  340. /*
  341.  * copy files
  342.  *    Usage:
  343.  *        cp src dest
  344.  *        or
  345.  *        cp files.. directory
  346.  */
  347. int cp(argc, argv)
  348. int argc;
  349. char **argv;
  350. {
  351.     char dest[128];
  352.     register int status;
  353.     extern int strlen();
  354.     extern int cpy();
  355.     extern char *basename();
  356.     
  357.     status = 0;
  358.     if(argc > 3)
  359.     {
  360.         register int i;
  361.  
  362.         if(!existd(argv[argc-1]))
  363.         {
  364.             fprintf(stderr,"%s does not exists or is not a directory\n",
  365.                 argv[argc-1]);
  366.             return 1;
  367.         }
  368.  
  369.         for(i = 1; i < argc - 1; i++)
  370.         {
  371.             strcpy(dest, argv[argc-1]);
  372.             if( (argv[argc-1])[(strlen(argv[argc-1])-1)] != '\\')
  373.                 strcat(dest, "\\");
  374.             strcat(dest, basename(argv[i]));
  375.  
  376.             fprintf(stderr,"copying %s to %s\n", argv[i], dest);
  377.             status |= cpy(argv[i], dest);
  378.         }
  379.     }
  380.     else
  381.     {
  382.         if(argc > 2)
  383.         {
  384.             if(existd(argv[2]))
  385.             {
  386.                 /* dest is a directory */
  387.                 strcpy(dest, argv[2]);
  388.                 if( (argv[2])[(strlen(argv[2])-1)] != '\\')
  389.                     strcat(dest, "\\");
  390.  
  391.                 strcat(dest, basename(argv[1]));
  392.  
  393.                 fprintf(stderr,"copying %s to %s\n", argv[1], dest);
  394.                 return (cpy(argv[1], dest));
  395.             }
  396.  
  397.             if(strcmp(argv[1], argv[2]) == 0)
  398.             {
  399.                 fprintf(stderr,"Cannot copy a file onto itself\n");
  400.                 return 3;
  401.             }
  402.             status = cpy(argv[1], argv[2]);
  403.         }
  404.         else
  405.         {
  406.             fprintf(stderr,"Usage: cp source dest or cp files .. directory\n");
  407.             return 2;
  408.         }
  409.     }
  410.  
  411.     return status;
  412. }
  413.  
  414.  
  415. /*
  416.  * Cpy src -> dest
  417.  *
  418.  */
  419. int cpy(src, dest)
  420. char *src, *dest;
  421. {
  422.     register int fps,fpd;
  423.     register long count;
  424.     register int status;
  425.  
  426.     status = 0;
  427.  
  428.     if((fps = Fopen(src, 0)) < (-3))
  429.     {
  430.         status = fps;
  431.         fprintf(stderr,"%s: no such file\n", src);
  432.         return status;
  433.     }
  434.  
  435.     if((fpd = Fcreate(dest, 0)) < (-3))
  436.     {
  437.         if((fpd = Fopen(dest, 1)) < (-3))
  438.         {
  439.             Fclose(fps);
  440.             status = fpd;
  441.             fprintf(stderr,"%s: cannot create\n",dest);
  442.             return status;
  443.         }
  444.     }
  445.     
  446.     while( (count = Fread(fps, (long)BBUFSIZ, bufr)) > 0L)
  447.     {
  448.         if(Fwrite(fpd, count, bufr) != count)
  449.         {
  450.             status = 1;
  451.             fprintf(stderr,"Error Writing %s\n",dest);
  452.             break;
  453.         }
  454.     }
  455.     if(count < 0L)
  456.     {
  457.         status = 2;
  458.         fprintf(stderr,"Error Reading %s\n", src);
  459.     }
  460.  
  461.     Fclose(fpd);
  462.     Fclose(fps);
  463.  
  464.     return status;
  465. }
  466.  
  467. #define haswild(X) \
  468. ( (rindex(X,'*') != (char *)NULL) || (rindex(X,'?') != (char *)NULL) )
  469.  
  470. /*
  471.  * list directories
  472.  */
  473. int ls(argc, argv)
  474. int argc;
  475. char **argv;
  476. {
  477.     char path[128];
  478.     register char *p;
  479.     extern char *rindex();
  480.     extern int existd();
  481.  
  482.     if(argc < 2)
  483.         lis("*.*");
  484.     else
  485.     {
  486.         while(--argc)
  487.         {
  488.             ++argv;
  489.             if((p = rindex(*argv,'\\')) == (char *)NULL)
  490.                 p = *argv;
  491.             else
  492.                 p++;
  493.             if(*p == '\0')
  494.             {
  495.                 strcpy(path, *argv);
  496.                 strcat(path,"*.*");
  497.             }
  498.             else
  499.             {
  500.                 if(haswild(p))
  501.                     strcpy(path, *argv);
  502.                 else
  503.                 {
  504.                     if(existd(p))
  505.                     {
  506.                         strcpy(path, *argv);
  507.                         strcat(path, "\\*.*");
  508.                     }
  509.                     else
  510.                         strcpy(path, *argv);
  511.                 }
  512.             }
  513.             lis(path);
  514.         } /* while */
  515.     }
  516.     
  517.     return 0;
  518. }
  519.  
  520. /*
  521.  * given a possibly wild carded string put out list of subtrees
  522.  *
  523.  */
  524. lis(wild)
  525. char *wild;
  526. {
  527.     extern struct stat statbuf;
  528.     register int count;
  529.  
  530. #ifdef DEBUG
  531. printf("ls %s\n", wild);
  532. #endif
  533.  
  534.     if(Fsfirst(wild, 0x0020 | 0x0010) != 0)
  535.     {
  536.         fprintf(stderr,"%s - no match.\n", wild);
  537.         return;
  538.     }
  539.  
  540.     count = 0;
  541.     alltolower(statbuf.st_name);
  542.     if(!((strcmp(statbuf.st_name,".") == 0) || 
  543.        (strcmp(statbuf.st_name, "..") == 0)))
  544.         putls(&statbuf, ++count);
  545.  
  546.     while(Fsnext() == 0)
  547.     {
  548.         alltolower(statbuf.st_name);
  549.         if(!((strcmp(statbuf.st_name,".") == 0) || 
  550.            (strcmp(statbuf.st_name, "..") == 0)))
  551.             putls(&statbuf, ++count);
  552.     }
  553.  
  554.     if((count % 4))
  555.         putc('\n', stderr);
  556.  
  557. }
  558.  
  559. /*
  560.  * Put out a directory entry
  561.  */
  562. putls(statbuf, count)
  563. register struct stat *statbuf;
  564. register int count;
  565. {
  566.     char dbuf[16];
  567.  
  568.     if((statbuf->st_mode) & 0x0010)
  569.     {
  570.         /* subtree */
  571.         strcpy(dbuf, statbuf->st_name);
  572.         strcat(dbuf, "/");
  573.         fprintf(stderr,"%-13s      ", dbuf);
  574.     }
  575.     else
  576.         /* file */
  577.         fprintf(stderr,"%-12s %5D ", statbuf->st_name, statbuf->st_size);
  578.     
  579.     if(!(count %4))
  580.         putc('\n', stderr);
  581. }
  582.  
  583. /*
  584.  * Change working directory
  585.  */
  586. int cd(argc, argv)
  587. int argc;
  588. char **argv;
  589. {
  590.     register char *d, *path;
  591.     register int drive;
  592.     extern char *index();
  593.  
  594.     if((argc < 2) || (argc > 2))
  595.     {
  596.         fprintf(stderr,"Usage: cd directory\n");
  597.         return 1;
  598.     }
  599.  
  600.  
  601.     
  602.     if((d = index(argv[1],':')) == (char *)NULL)
  603.     {
  604.         /* Drive was not specified, must mean the current drive */
  605.         path = argv[1];
  606.     }
  607.     else
  608.     {
  609.         d--;
  610.         if(isupper(*d))
  611.         {
  612.             *d = tolower(*d);
  613.         }
  614.         drive = *d - 'a';
  615.         if(d[2] != '\\')    /* just gave D: */
  616.         {
  617.             /* we will shove in the '\' */
  618.             d[1] = '\\';
  619.             path = &d[1];
  620.         }
  621.         else
  622.             path = &d[2];
  623.  
  624.         /* Set the Drive */
  625.         if(Dsetdrv(drive) < 0)
  626.         {
  627.             fprintf(stderr,"Could not set drive %c:\n", *d);
  628.             return 2;
  629.         }
  630.  
  631.     }
  632.  
  633.  
  634.     /* Set the Path */
  635.     if(Dsetpath(path) != 0)
  636.     {
  637.         fprintf(stderr,"Could not set directory %s\n", path);
  638.         return 3;
  639.     }
  640.     
  641.     return 0;
  642.     
  643. }
  644.  
  645. /*
  646.  * pwd - figure out the current working directory
  647.  *
  648.  */
  649. int pwd()
  650. {
  651.     register int drive;
  652.     char _cwd[128];
  653.     
  654.     drive = Dgetdrv();
  655.     Dgetpath(&_cwd[3],0);
  656.     fprintf(stderr,"%c:%s%s\n", (drive + 'a'),
  657.         ((_cwd[3] == '\\')? "" : "\\"), &_cwd[3]);
  658.  
  659.     return 0;
  660. }
  661.  
  662. /*
  663.  * Print free space
  664.  */
  665. int df(argc, argv)
  666. int argc;
  667. char **argv;
  668. {
  669.     struct {
  670.         long b_free;
  671.         long b_total;
  672.         long b_secsiz;
  673.         long b_clsiz;
  674.     } fbuf;
  675.  
  676.     register int drive;
  677.     register long ffree, total;
  678.     extern long drv_map;
  679.  
  680.     if(argc > 1)
  681.     {
  682.         ++argv;
  683.         drive = (*argv)[0];
  684.         if(isupper(drive))
  685.             drive = tolower(drive);
  686.  
  687.         drive = drive - 'a';
  688.         if((drv_map & (1L << drive)) == 0)
  689.         {
  690.             fprintf(stderr,"Invalid Drive %c:\n", (drive + 'a'));
  691.             return 1;
  692.         }
  693.         drive +=1;
  694.     }
  695.     else
  696.         drive = Dgetdrv()+1;    /* default current drive */
  697.  
  698.     fprintf(stderr,"Please Wait .....");
  699.     Dfree(&fbuf,drive);
  700.     ffree = fbuf.b_free * fbuf.b_clsiz * fbuf.b_secsiz;
  701.     total =    fbuf.b_total * fbuf.b_clsiz * fbuf.b_secsiz;
  702.     fprintf(stderr,"\r%ld Bytes (", ffree);
  703.     prratio(stderr, ffree, total);
  704.     fprintf(stderr, ") Free on drive %c:\n", ((drive-1) + 'a'));
  705.  
  706.     return 0;
  707. }
  708.  
  709.  
  710. /*
  711.  * print a ratio
  712.  * avoid floats like the plague
  713.  */
  714. prratio(stream, num, den)
  715. FILE *stream;
  716. long  num, den;
  717. {
  718.         register int q;                 /* Doesn't need to be long */
  719.  
  720.         if(num > 214748L) {             /* 2147483647/10000 */
  721.                 q = num / (den / 10000L);
  722.         } else {
  723.                 q = 10000L * num / den;         /* Long calculations, though */
  724.         }
  725.         if (q < 0) {
  726.                 putc('-', stream);
  727.                 q = -q;
  728.         }
  729.         fprintf(stream, "%d.%02d%%", q / 100, q % 100);
  730. }
  731.  
  732. /*
  733.  * Make directories
  734.  */
  735. int md(argc, argv)
  736. int argc;
  737. char **argv;
  738. {
  739.     register int status, s;
  740.  
  741.     status = 0;
  742.     while(--argc)
  743.     {
  744.         ++argv;
  745.         if(( s = Dcreate(*argv)))
  746.         {
  747.             status |= s;
  748.             fprintf(stderr,"Could not create %s\n", *argv);
  749.         }
  750.     }
  751.  
  752.     return status;
  753. }
  754.  
  755. /*
  756.  * Remove directories
  757.  */
  758. int rd(argc, argv)
  759. int argc;
  760. char **argv;
  761. {
  762.     register int status, s;
  763.  
  764.     status = 0;
  765.     while(--argc)
  766.     {
  767.         ++argv;
  768.         if(( s = Ddelete(*argv)))
  769.         {
  770.             status |= s;
  771.             fprintf(stderr,"Could not delete %s\n", *argv);
  772.         }
  773.     }
  774.  
  775.     return status;
  776. }
  777.  
  778.  
  779. /*
  780.  * Allocate memory with error check
  781.  *
  782.  */
  783. char *myalloc(size)
  784. unsigned int size;
  785. {
  786.     register char *m;
  787.     extern char *malloc();
  788.  
  789.     if((m = malloc(size)) == (char *)NULL)
  790.     {
  791.         fprintf(stderr,"Out of Memory\nSorry, cannot continue\n");
  792.         exit(1);
  793.     }
  794.  
  795.     return m;
  796. }
  797.  
  798. /*
  799.  * Put out help
  800.  */
  801. int hhelp()
  802. {
  803.     register int i;
  804.  
  805.     fprintf(stderr,"\n\t\t\t   \033p Available Commands \033q\n\n");
  806.     for(i = 0; comtab[i].command != (char *)NULL; i++)
  807.     {
  808.         fprintf(stderr,"\t%s\t%s\n", comtab[i].command,
  809.             comtab[i].synopsis);
  810.     }
  811.     fprintf(stderr,"\n\tor hit <RETURN> to exit to terminal emulator\n\n");
  812.     return 0;
  813.  
  814. }
  815.  
  816. /*
  817.  * Lower case string
  818.  */
  819. char *alltolower(s)
  820. register char *s;
  821. {
  822.     register char *p;
  823.  
  824.     for(p = s; *p != '\0'; p++)
  825.     {
  826.         if(isupper(*p))
  827.             *p = tolower(*p);
  828.     }
  829.     return s;
  830. }
  831.  
  832. /*
  833.  * return the base filename, given (potentially) a pathname
  834.  */
  835. char *basename(s)
  836. register char *s;
  837. {
  838.     register char *p;
  839.     extern char *rindex();
  840.  
  841.     if((p = rindex(s, '\\')) == (char *)NULL)
  842.     {
  843.         if((p = rindex(s, ':')) == (char *)NULL)
  844.             return s;
  845.         else
  846.             return ++p;
  847.     }
  848.     return ++p;
  849. }
  850.  
  851. #ifdef RECURSE
  852. int doszf(argc, argv)
  853. int argc;
  854. char **argv;
  855. {
  856.     extern int expandargs();
  857. #ifdef DDEBUG
  858. int i;
  859. printf("doszf: argc %d\n", argc);
  860. for(i = 0; i < argc; i++)
  861.     printf("%s ", argv[i]);
  862. printf("\n\n");
  863. #endif
  864.  
  865.     return(expandargs(dosz, argc, argv));
  866. }
  867.  
  868. #include "expandar.c"
  869.  
  870. #endif
  871.  
  872. /** EOF **/
  873.